package controle;

import java.awt.Color;
import java.util.ArrayList;

import componentes.Alvo;
import componentes.Aviao;
import componentes.Projetil;

import interfaces.PainelFase;

/**
 * 
 * Classe ProjetilThread.java que representa a thread que executa o controle
 * sobre o movimento de um projétil
 * 
 * @desc Projeto BombarJ
 * @author Simone Carneiro Streitenberger 11888 CCO2003
 * @author Thiago Nascimento Comicio 11889 CCO2003
 * @professor Edison de Jesus
 * @disciplina Computação Gráfica 2 - CCO812
 * 
 */
public class ProjetilThread extends Thread {
	// projétil que será movimentado
	private Projetil projetil;

	// painel onde será impresso o projétil
	private PainelFase painel;

	// aviao de onde partirá o projétil
	private Aviao aviao;

	// lista de alvos para verificar colisão
	private ArrayList<Alvo> alvos;

	// cor da fase
	private Color corFase;

	// indica se a thread deve ser terminada
	private int destrua;

	// indica o pause do projétil
	private boolean pause;

	// objeto de controle onde esta classe se conecta
	private Controle controle;

	/**
	 * 
	 * Construtor da classe ProjetilThread.java
	 * 
	 * @param painel
	 * @param projetil
	 * @param aviao
	 * @param alvos
	 */
	public ProjetilThread(PainelFase painel, Projetil projetil, Aviao aviao,
			ArrayList<Alvo> alvos, Color corFase, Controle controle) {

		this.painel = painel;
		this.projetil = projetil;
		this.aviao = aviao;
		this.alvos = alvos;
		this.corFase = corFase;
		this.controle = controle;

		this.pause = false;

		SomThread somThread = new SomThread("sons/laser_1.au");
		somThread.start();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Thread#run()
	 */
	public void run() {

		// indica a quantidade de milisegundos que a thread deve interromper
		final int dormir = 15;

		// posições do projétil
		int y0, y, x = 0, xAnt = -300;
		double t;

		// constantes em relação a trajetória
		final double g = 9.8;
		final double parcelaTempo = (double) (dormir) / 80.0;

		t = parcelaTempo;

		// seleciona a posição incial de y
		y0 = aviao.getPosicaoCentroRelOrigem().getY();

		// loop que ocorre ateh q destrua seja igual a 1
		for (;;) {

			// verifica se o jogo está pausado
			if (!pause) {

				// calcula nova posição do projétil
				y = y0 + (int) Math.round(g * (double) (t * t) / 2.0);
				x = aviao.getPosicaoCentroRelOrigem().getX();

				// seta a nova posição do projétil
				projetil.setPosicao(x, y);

				// verifica a colisão a aprtir de uma detrminada altura
				if (y >= painel.getHeight() - alvos.get(0).getTamanho() - 20) {
					verificaColisao();
				}

				// repinta o painel com a nova posição do projétil
				painel.repaint();

				// interrompe a thread por "dormir" milisegundos
				try {
					Thread.sleep(dormir);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				// verifica se extrapolou a tela
				if (xAnt != -300) {
					if (Math.abs(x - xAnt) > 100) {
						destrua = 1;

						// verifica a quantidade de projéteis e termina o jogo
						if ((controle.getNumProjeteis() == 0)
								&& (controle.getNumProjeteisExtra() == 0)) {
							controle.terminaJogo();
						}

					}
				}
				xAnt = x;

				// verifica se acertou o chao
				if (y > painel.getHeight() + 30) {
					destrua = 1;

					// verifica a quantidade de projéteis e termina o jogo
					if ((controle.getNumProjeteis() == 0)
							&& (controle.getNumProjeteisExtra() == 0)) {
						controle.terminaJogo();
					}
				}

				// indica a soma do tempo
				t += parcelaTempo;
			}

			// verifica se a thread deve ser terminada
			if (destrua == 1) {
				painel.removeProjetil(projetil);
				break;
			}
		}
	}

	/**
	 * 
	 * Método que tem por função verificar se ocorreu alguma colisão entre os
	 * alvos e o projétil
	 * 
	 */
	private void verificaColisao() {

		// pega cada um dos alvos e verifica
		for (Alvo alvo : alvos) {

			// seta os valores para mais fácil entendimento
			int yMin = painel.getHeight() - alvo.getTamanho();
			int yMax = painel.getHeight();
			int xMin = alvo.getX();
			int xMax = xMin + alvo.getLargura();

			int xPro = projetil.getCentral().getX();
			int yPro = projetil.getCentral().getY();

			int raio = projetil.getRaio();

			/* verificação da parede esquerda */
			if (Math.abs(xPro - xMin) <= raio) {
				if ((yPro > yMin) && (yMax > yPro)) {
					destrua = 1;
				}
			}

			/* verificação da parede direita */
			if (Math.abs(xPro - xMax) <= raio) {
				if ((yPro > yMin) && (yMax > yPro)) {
					destrua = 1;
				}
			}

			/* verificação da parede superior */
			if (Math.abs(yPro - yMin) <= raio) {
				if ((xPro > xMin) && (xMax > xPro)) {
					destrua = 1;
				}
			}

			/* verificação da parte interna */
			if ((yMin <= yPro) && (yPro <= yMax) && (xMin <= xPro)
					&& (xPro <= xMax)) {
				destrua = 1;
			}

			// troca a cor do alvo
			if (destrua == 1) {
				if (alvo.getCor() != corFase) {
					alvo.setCor(corFase);

					// verifica o game over
					if ((controle.getNumProjeteis() == 0)
							&& (controle.getNumProjeteisExtra() == 0)
							&& (controle.getAlvosAcertar() > 1)) {
						controle.terminaJogo();
					}

					controle.acertoAlvo();
				} else {

					// verifica o game over
					if ((controle.getNumProjeteis() == 0)
							&& (controle.getNumProjeteisExtra() == 0)) {
						controle.terminaJogo();
					}

					alvo.setCor(Color.BLACK);
					controle.reacertoAlvo();
				}

				return;
			}
		}
	}

	/**
	 * 
	 * Método que tem por função indicar que a thread deve ser terminada
	 * 
	 */
	public void destrua() {
		destrua = 1;
	}

	/**
	 * 
	 * Método que tem por função conectar ao objeto de controle
	 * 
	 * @param controle
	 *            Objeto de controle da aplicação.
	 * 
	 */
	public void concetaControle(Controle controle) {
		this.controle = controle;
	}

	/**
	 * 
	 * Método que retorna o valor do atributo destrua.
	 * 
	 * @return O atributo destrua.
	 * 
	 */
	public int getDestrua() {
		return destrua;
	}

	/**
	 * 
	 * Método que seta o atributo destrua para um novo valor.
	 * 
	 * @param destrua
	 *            O atributo destrua � setado.
	 * 
	 */
	public void setDestrua(int destrua) {
		this.destrua = destrua;
	}

	/**
	 * 
	 * Método que retorna o valor do atributo painel.
	 * 
	 * @return O atributo painel.
	 * 
	 */
	public PainelFase getPainel() {
		return painel;
	}

	/**
	 * 
	 * Método que seta o atributo painel para um novo valor.
	 * 
	 * @param painel
	 *            O atributo painel � setado.
	 * 
	 */
	public void setPainel(PainelFase painel) {
		this.painel = painel;
	}

	/**
	 * 
	 * Método que retorna o valor do atributo pause.
	 * 
	 * @return O atributo pause.
	 * 
	 */
	public boolean isPause() {
		return pause;
	}

	/**
	 * 
	 * Método que seta o atributo pause para um novo valor.
	 * 
	 * @param pause
	 *            O atributo pause � setado.
	 * 
	 */
	public void setPause(boolean pause) {
		this.pause = pause;
	}

	/**
	 * 
	 * Método que retorna o valor do atributo projetil.
	 * 
	 * @return O atributo projetil.
	 * 
	 */
	public Projetil getProjetil() {
		return projetil;
	}

	/**
	 * 
	 * Método que seta o atributo projetil para um novo valor.
	 * 
	 * @param projetil
	 *            O atributo projetil � setado.
	 * 
	 */
	public void setProjetil(Projetil projetil) {
		this.projetil = projetil;
	}

}
